package com.sojson.websocket.config;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.sojson.constant.Constant;
import com.sojson.util.init.InitUtil;
import com.sojson.util.text.Convert;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * WebSocket配置类
 *
 * @author liu
 * @date 2024-06-04
 */
@Slf4j
@Component
public class WebSocketConfig {

    @Autowired
    WebSocketHandler handler;
    String path = "/skt";
    int port = Convert.toInt(Constant.PROPERTIES.getProperty("so.server.port"), 8080) + 1;
    /** 负责监听 */
    private EventLoopGroup bossGroup = new NioEventLoopGroup(2);
    /** 负责读取 */
    EventLoopGroup workGroup = new NioEventLoopGroup(8);

    @PostConstruct
    public void start() throws InterruptedException {
        // 工作线程池
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup)
            // 指定 nio 通道，支持 WebSocket
            .channel(NioServerSocketChannel.class)
            // 设置读取缓冲区大小为 10M
            .option(ChannelOption.SO_RCVBUF, 1024 * 1024 * 10)
            // 线程池复用缓冲区
            .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
            // 队列大小
            .option(ChannelOption.SO_BACKLOG, 128)
            // 添加通道 handler
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline p = socketChannel.pipeline();
                    p.addLast(new HttpServerCodec());
                    p.addLast(new HttpObjectAggregator(port));
                    p.addLast(new WebSocketServerProtocolHandler(path));
                    p.addLast(handler);
                    // 指定工作线程，提高并发性能
                    p.addLast(workGroup, handler);
                }
            });

        // 开启需要监听 的端口
        ChannelFuture future = bootstrap.bind(port).sync();
        if (future.isSuccess()) {
            InitUtil.add(new StringBuilder("WebSocket服务启动成功，地址为: ").append(path).append(":").append(port).toString());
        } else {
            InitUtil.add(new StringBuilder("WebSocket服务启动失败，地址为: ").append(path).append(":").append(port).toString());
        }
    }

    @PreDestroy
    public void destroy() {
        try {
            bossGroup.shutdownGracefully().syncUninterruptibly();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        try {
            workGroup.shutdownGracefully().syncUninterruptibly();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        log.info("关闭 WebSocket 成功");
    }

}